/*Arduino Whack-A-Mole Game by mircemk, June 2025 */ #include #include LiquidCrystal_I2C lcd(0x27, 16, 2); // Pin Definitions const int buttonPins[] = {8, 9, 10, 11, 12}; // Button pins const int ledPins[] = {2, 3, 4, 5, 6}; // LED pins const int buzzerPin = 13; // Buzzer pin (digital 13) const int numMoles = 5; // Number of moles/buttons/LEDs // Game variables int currentMole = -1; // Current mole (LED) to be lit int score = 0; // Player's score unsigned long reactionTime = 1000; // Initial reaction time (milliseconds) unsigned long lastMoleTime = 0; // Time when the last mole was lit unsigned long gameStartTime = 0; // Start time of the game unsigned long gameDuration = 30000; // Total game duration (30 seconds) // Reaction time adjustment const unsigned long reactionTimeDecrement = 100; // Time to reduce reaction by (milliseconds) const unsigned long minReactionTime = 300; // Minimum reaction time (milliseconds) void setup() { lcd.backlight(); lcd.begin(16, 2); lcd.clear(); lcd.setCursor(2, 0); lcd.print("Whack-a-Mole"); lcd.setCursor(3, 1); lcd.print("by mircemk"); delay(2000); lcd.clear(); // Initialize button pins and LED pins for (int i = 0; i < numMoles; i++) { pinMode(buttonPins[i], INPUT_PULLUP); // Set button pins as input with pull-up resistors pinMode(ledPins[i], OUTPUT); // Set LED pins as output digitalWrite(ledPins[i], LOW); // Turn off all LEDs initially } pinMode(buzzerPin, OUTPUT); // Set buzzer pin as output Serial.begin(9600); // For debugging and displaying the score randomSeed(analogRead(0)); // Initialize random seed from an unused analog pin Serial.println("Whack-a-Mole Game Started!"); lcd.setCursor(2, 0); lcd.print("GAME STARTED!"); delay(500); lcd.clear(); gameStartTime = millis(); // Record game start time } void loop() { unsigned long currentMillis = millis(); // Get the current time // Update the progress bar unsigned long elapsedTime = currentMillis - gameStartTime; if (elapsedTime <= gameDuration) { int barLength = map(gameDuration - elapsedTime, 0, gameDuration, 0, 16); lcd.setCursor(0, 1); for (int i = 0; i < 16; i++) { lcd.print(i < barLength ? '-' : ' '); // Print '-' for remaining time, ' ' for elapsed } } // Light up a mole after a certain amount of time (based on reactionTime) if (currentMillis - lastMoleTime >= reactionTime) { if (currentMole != -1) { digitalWrite(ledPins[currentMole], LOW); // Turn off the previous mole } currentMole = random(0, numMoles); // Randomly pick a mole (LED) digitalWrite(ledPins[currentMole], HIGH); // Light up the chosen LED lastMoleTime = currentMillis; // Update the time when the mole was lit } // Check if the player pressed the correct button for the lit mole for (int i = 0; i < numMoles; i++) { if (digitalRead(buttonPins[i]) == LOW) { // Button pressed (LOW due to INPUT_PULLUP) if (i == currentMole) { score++; // Correct mole hit lcd.setCursor(2, 0); lcd.print(" Score: "); // Clear the score field with extra spaces lcd.setCursor(12, 0); lcd.print(score); // Update the score tone(buzzerPin, 1000, 200); // High-pitched sound (1000Hz) for 200ms if (reactionTime > minReactionTime) { reactionTime -= reactionTimeDecrement; } } else { score--; // Wrong mole hit lcd.setCursor(2, 0); lcd.print(" Score: "); // Clear the score field with extra spaces lcd.setCursor(12, 0); lcd.print(score); // Update the score tone(buzzerPin, 400, 200); // Low-pitched sound (400Hz) for 200ms } digitalWrite(ledPins[currentMole], LOW); // Turn off the current mole currentMole = -1; // Reset the mole to indicate no active mole delay(500); // Short delay to debounce button press } } // End the game after the set duration if (elapsedTime >= gameDuration) { lcd.setCursor(3, 0); lcd.print("Game Over! "); lcd.setCursor(0, 1); lcd.print("Final Score: "); lcd.setCursor(13, 1); lcd.print(" "); // Clear any leftover characters lcd.setCursor(13, 1); lcd.print(score); // Print the final score // Flash all LEDs and play a sound three times for (int i = 0; i < 3; i++) { for (int j = 0; j < numMoles; j++) { digitalWrite(ledPins[j], HIGH); } tone(buzzerPin, 1000, 300); // Play sound delay(300); // Keep LEDs on for (int j = 0; j < numMoles; j++) { digitalWrite(ledPins[j], LOW); } delay(300); // Keep LEDs off } delay(2000); // Pause before resetting the game lcd.clear(); score = 0; currentMole = -1; for (int i = 0; i < numMoles; i++) { digitalWrite(ledPins[i], LOW); } lcd.setCursor(0, 0); lcd.print(" Start New Game"); delay(5000); lcd.clear(); gameStartTime = millis(); reactionTime = 1000; } }